home *** CD-ROM | disk | FTP | other *** search
- ;*************************************************************************
- ;** mmu.library **
- ;** **
- ;** a system library for arbitration and control of the MC68K MMUs **
- ;** **
- ;** © 1998 THOR-Software, Thomas Richter **
- ;** No commercial use, reassembly, modification without prior, written **
- ;** permission of the authors. **
- ;** Including this library in any commercial software REQUIRES a **
- ;** written permission and the payment of a small fee. **
- ;** **
- ;** This is an internal header file, do not depend on anything here. **
- ;** Use the official include files. **
- ;** Distributed only for the mmu.library development group for private **
- ;** use. **
- ;** **
- ;**---------------------------------------------------------------------**
- ;** New Unified table scanner, (NUTS) Version 0.00 **
- ;** © 1998 THOR-Software **
- ;*************************************************************************
-
- ;FOLD Includes
- include inc:macros.asm
- include inc:exec_lib.asm
- include mu_lib.i
- include mu_context.i
- include mu_descriptor.i
- include kaputstr.i
- ;ENDFOLD
- ;FOLD External References
- xref LockContext
- xref UnlockContext
- xref MUAlert
- xref FreePointerTable
- xref DefineMapping
- ;ENDFOLD
- ;FOLD Defines
- ;ENDFOLD
-
- section main_code,code
- machine mc68020
-
- ;FOLD ParseMMUTable
- ;*************************************************
- ;** ParseMMUTable **
- ;** parse the MMU table given by the config **
- ;** *a1, to the Context *a0 **
- ;** d0=TRUE: worked fine **
- ;*************************************************
- xdef ParseMMUTable
- ParseMMUTable:
- saveregs d2/d4/a5
- defvar
- auto.b pmt_descriptor,atd_len
- endvar
-
- move.l a0,a5 ;keep the context in a5
- bsr LockContext
-
- move.l a7,a0
- jsr mulib_RootStarter(a6) ;get the root descriptor
- move.l d0,d2 ;an error ?
- beq.s .errorexit
- bpl.s .disabled ;it's just disabled!
-
- move.l atd_Pointer(a7),a1 ;read this pointer
- move.l a7,a0 ;fill in this type
- move.b atd_NextType(a7),d0 ;type of the descriptor to be read
- moveq #0,d1 ;masking is levelA
- jsr mulib_ReadDescriptor(a6) ;read it
-
- sub.l a1,a1 ;address to be scanned: 0
- move.l a7,a0 ;table descriptor of this level
- moveq #0,d0 ;current level
- bsr.s RecursiveScan ;and now, scan it
- bne.s .disabled ;worked? return TRUE
-
- moveq #0,d2
- bra.s .errorexit
-
- .disabled:
- moveq #-1,d2 ;don't scan the table, just use the prepared stuff
- .errorexit:
- move.l a5,a0
- bsr UnlockContext
- move.l d2,d0
-
- freevar
- loadregs
- rts
- ;ENDFOLD
- ;FOLD RecursiveScan
- ;*************************************************
- ;** RecursiveScan **
- ;** Scan the abstract descriptor at *a0 **
- ;** recursively **
- ;** it describes address base a1 at level d0 **
- ;** (d0=-1 is root level, i.e. the descriptor **
- ;** points effectively to the user root pointer **
- ;** in the MMU configuration) **
- ;** *a5 is the context (already locked) **
- ;** **
- ;** returns 0 in case of failure **
- ;** returns 2 if this level of the tree **
- ;** consists purely of one type of properties **
- ;** so we may take a shortcut if we find a **
- ;** descriptor pointing to the same branch **
- ;** of the tree **
- ;** in this case, properties and data are **
- ;** filled into d1 and a0 **
- ;** returns 1 if no shortcut possible **
- ;*************************************************
- RecursiveScan:
- saveregs d2-d7/a2-a4
- defvar
- auto.b rcs_descriptor,atd_len
- auto.l rcs_increment ;from one to the next descriptor of the table
- auto.l rcs_entries ;#of entries on that level of the table
- auto.l rcs_lastproperties
- auto.l rcs_lastpointer
- auto.l rcs_lastbase
- auto.b rcs_continuous
- auto.b rcs_tableshift
- auto.w rcs_nextlevel
- auto.w rcs_lastindex
- auto.b rcs_lasttableshift
- auto.b rcs_thistype ;backup of atd_thistype
- endvar
-
- kaputstr "{"
-
- move.l a0,a2 ;keep atd
- move.l d0,d4 ;keep level
- move.l a1,a4 ;keep base address
- addq.w #1,d0 ;next level
- tst.b ctx_LevelABits(a5,d0.w) ;is there a next level ?
- bne.s .gotnext
- moveq #4,d0 ;at page level
- .gotnext:
- clr.l rcs_lastpointer(a7)
- move.w d0,rcs_nextlevel(a7)
- move.l #(1<<mapp_invalid),rcs_lastproperties(a7)
-
- st.b rcs_continuous(a7) ;mapping is continous
- move.l ctx_LevelATableSz(a5,d4.w*4),d3 ;lower limit greater than table size ?
- moveq #0,d7
- move.b ctx_LevelAPos(a5,d4.w),d5 ;bit position in the address of this level
- subq.l #1,d3
- add.b ctx_LevelABits(a5,d4.w),d5 ;position of the LSB instead of MSB
- moveq #0,d0
- move.b d5,rcs_tableshift(a7)
-
- move.w atd_LowerLimit(a2),d0 ;do we have a lower limit ?
- beq.s .nolowerlimit
- ;yup!
- clr.b rcs_continuous(a7) ;mapping is no longer continous
- moveq #0,d5 ;lower
- move.l d0,d6 ;upper: up to here no access
- moveq #0,d1 ;no user data
- cmp.l d3,d6 ;is the upper level useful ?
- bls.s .nocut
- move.l d3,d6 ;but not more than all descriptors at this level
- .nocut:
- move.l #(1<<mapp_invalid),d0 ;type is invalid
- bsr _SetPageRange ;mark this range as invalid
- beq .exit ;on error exit
- .nolowerlimit:
- moveq #0,d7
- moveq #0,d6
- move.w atd_UpperLimit(a2),d7 ;get upper limit
- move.w atd_LowerLimit(a2),d6 ;and lower
- cmp.l d3,d7 ;must not be greater than that!
- bls.s .nocuthigher
- move.l d3,d7 ;restrict to this value
- .nocuthigher:
- move.l a2,a0
- move.w d6,d0
- jsr mulib_ReadIncrement(a6) ;get increment and pointer
- movem.l d0/d3,rcs_increment(a7) ;keep increment,# entries
- move.l a0,a3 ;Pointer -> a3
-
- kaputstr <"index range %lx to %lx">,d6,d7
-
- do
- cmp.w d7,d6 ;are we out of range ?
- break hi ;abort, if so. Range is inclusive
-
- kaputstr <"index processed %lx">,d6
-
- move.l a7,a0
- move.l a3,a1
- move.b atd_NextType(a2),d0 ;type
- move.w rcs_nextlevel(a7),d1 ;level
- move.b d0,rcs_ThisType(a7) ;keep me
- jsr mulib_ReadDescriptor(a6) ;read the descriptor
-
-
- move.l atd_Properties(a2),d1
-
- kaputstr <"descriptor (%08lx), properties %08lx">,(a3),d1
-
- move.b atd_ThisType(a7),d0 ;get type of this one
- or.l d1,atd_Properties(a7) ;collect property flags
- and.b #3,d0 ;ignore size
- cmp.b #atdt_indirect,d0 ;is this propably indirect ?
- bne.s .noindirect
- ;if so, increase the level temporarely and
- ;reference the indirect pointer
- move.l a7,a0
- move.l atd_Pointer(a7),a1
-
- kaputstr <"indirect descriptor (%08lx)">,(a1)
-
- moveq #5,d1 ;level is indirection
- move.b atd_NextType(a7),d0 ;type of this descriptor
- jsr mulib_ReadDescriptor(a6) ;double indirection is not allowed and
- move.b rcs_ThisType(a7),d1 ;get type again
- ;hopefully regarded as invalid by ReadDescriptor
- move.b atd_ThisType(a7),d0 ;read type again
- and.b #$fc,d1
- and.b #3,d0
- or.b #atdt_indirect,d1 ;mark this as indirect
- move.b d1,rcs_ThisType(a7)
- .noindirect:
- tst.b d0
- beq .invalid ;invalid ?
- cmp.b #atdt_table,d0 ;is this propably a page descriptor ?
- beq .table
- .page: ;here: we got a page descriptor
- ;check now, how many page descriptors of
- ;the same type follow in sequence.
- ;two things could happen:
- ;a) a continous mapping of logical
- ;addresses to physical.
- ;this means specifically that we
- ;need to add an offset to each compare
- ;b) a "bundled" mapping of logical
- ;addresses to all the same physical
- ;page. This might be done by certain
- ;system software to map out
- ;complete pages without creating a
- ;bus error on access and is similar to
- ;what this library does on "tolerated"
- ;pages.
-
- ;first, we handle early page
- ;descriptors with limits
- move.w rcs_nextlevel(a7),d0
- cmp.w #4,d0 ;page level descriptors never carry limits
- bge .nolimit
- move.l ctx_LevelATableSz(a5,d0.w*4),d3 ;required to bound the limits
- movem.w atd_LowerLimit(a7),d0-d1 ;get lower and upper limit
- subq.l #1,d3
- cmp.w d3,d0
- bls.s .nocutlower2
- move.l d3,d0
- .nocutlower2:
- cmp.w d3,d1
- bls.s .nocuthigher2
- move.l d3,d1
- .nocuthigher2:
- tst.w d0 ;do we have a lower limit ?
- bne.s .withlimit
- cmp.w d3,d1 ;do we have a higher limit ?
- beq .nolimit
- .withlimit:
-
- ;here: we got a limit
- ;clr.b rcs_continuous(a7) ;this is never continous
- ;will be cleared below
- move.l a4,rcs_lastbase(a7)
- move.b rcs_tableshift(a7),d2
- move.l d6,d5
- move.b d2,rcs_lasttableshift(a7)
- movem.w d0-d1,atd_LowerLimit(a7) ;keep limits
- ror.l d2,d5 ;shift delta in place
- move.w rcs_nextlevel(a7),d1
- adda.l d5,a4 ;new base address
- add.b ctx_LevelABits(a5,d1.w),d2 ;increment tableshift
- move.w d6,rcs_lastindex(a7) ;save this guy, too
- move.b d2,rcs_tableshift(a7) ;saveback tableshift for stack magic
-
- tst.w d0 ;do we have a lower limit ?
- beq.s .nolowerpagelimit
- moveq #0,d5 ;if so, disable this to
- move.l d0,d6 ;to this
- move.l #(1<<mapp_invalid),d0
- moveq #0,d1
- bsr _SetPageRange
- beq .exit
- .nolowerpagelimit:
- movem.w atd_LowerLimit(a7),d5-d6 ;restore limits
- cmp.l d6,d5 ;is something left ?
- bhi.s .nocontents
- move.l atd_Pointer(a7),d1 ;get page pointer
- move.l atd_Properties(a7),d0 ;get properties
- addq.l #1,d6
- sub.l a4,d1 ;do we have a delta ?
- beq.s .nodeltapage
- bset #mapp_remapped,d0 ;if so, enable remapped
- .nodeltapage:
- bsr _SetPageRange
- beq .exit
- subq.l #1,d6
- .nocontents:
- cmp.l d3,d6 ;do we have an upper limit ?
- beq.s .noupperpagelimit
- move.l d6,d5
- move.l #(1<<mapp_invalid),d0 ;is invalid
- move.l d3,d6 ;from here to there
- addq.l #1,d5
- addq.l #1,d6
- moveq #0,d1 ;no user data
- bsr _SetPageRange
- beq .exit
- .noupperpagelimit:
- moveq #0,d6
- move.b rcs_lasttableshift(a7),rcs_tableshift(a7) ;restore tableshift
- move.w rcs_lastindex(a7),d6 ;restore index from above
- move.l rcs_lastbase(a7),a4 ;restore base pointer
- addq.w #1,d6 ;next entry
- bra .nexttable ;this clears rcs_continous to
-
- .nolimit:
- move.l d6,d5 ;keep initial entry
- move.l a3,a0
- move.l rcs_increment(a7),d2 ;get increment
- cmp.w d7,d5 ;compare with the maximum. No need to bundle if this is the last one
- beq.s .lastpage
- lea (a3,d2.l),a1 ;get the next one
- ;obviously, the same page descriptor is
- ;identical to itself, so we have to scan the next
- moveq #0,d1 ;no offset
- move.b rcs_ThisType(a7),d0 ;and type of this guy
- jsr mulib_CmpDescriptor(a6) ;are these the same ?
- beq.s .bundled ;if so, these are declared as "bundled"
- ;they map all to the same phyical address
- .lastpage: ;only one page, then remapped, not bundled
- ;here: unbundled, we need to add an offset
- move.l a3,a1 ;start over
- move.l ctx_LevelASize(a5,d4.w*4),d3 ;get increment, i.e. the range of logical addresses this
- ;descriptor covers
- moveq #0,d2 ;clear initial increment
- do
- cmp.w d7,d6 ;are we done with that table completely ?
- bhi.s .donepage
- move.l d2,d1 ;this delta
- move.b rcs_ThisType(a7),d0 ;type of the descriptor we're pointing to
- move.l a1,a3 ;keep pointer for later
- jsr mulib_CmpDescriptor(a6) ;compare if the two descriptors are equal
- break.s ne ;abort if not
- add.l d3,d2 ;add the size of a early termination page at this level
- addq.w #1,d6 ;continue with the next entry
- loop.s
- .donepage:
- clr.b rcs_continuous(a7) ;pages can never be shortcutted
- move.l d5,d0
- move.b rcs_tableshift(a7),d1
- ror.l d1,d0
- move.l atd_Pointer(a7),d1 ;data is page address
- lea (a4,d0.l),a0
- move.l atd_Properties(a7),d0 ;get properties
- sub.l a0,d1 ;do we map this to the physical page ?
- beq.s .noremap
- bset #mapp_remapped,d0 ;this page is mapped to somewhere else
- .noremap:
- bsr _SetPageRange
- beq .exit
- reloop
-
-
- .bundled: ;now again the same sport:
- ;find as many bundled addresses as possible
- move.l a3,a1 ;start over from here. At least ONE will be the result
- do
- cmp.w d7,d6 ;are we done with that table completely ?
- bhi.s .donebundled
- moveq #0,d1 ;no deltas. These MUST be literally the same
- move.b rcs_ThisType(a7),d0 ;type of the descriptor we're pointing to
- move.l a1,a3 ;keep pointer for later
- jsr mulib_CmpDescriptor(a6) ;compare if the two descriptors are equal
- break.s ne ;abort if not
- addq.w #1,d6 ;continue with the next entry
- loop.s
- ;here: abort before the table went out of data
- clr.b rcs_continuous(a7) ;nope, this table is clearly not continous of one type
- .donebundled: ;we're done. Found [d5,d6] bundled entries
- move.l atd_Properties(a7),d0 ;get properties
- move.l atd_Pointer(a7),d1 ;data is page address
- bset #mapp_bundled,d0 ;adjust the properties of this guy
- bsr _SetPageRange
- beq .exit
- reloop
-
- .invalid: ;here: found an invalid descriptor
- ;check, how many invalid descriptors follow
- move.l d6,d5 ;and setup a complete range of them
- move.l a3,a0 ;get the descriptor again
- move.l a3,a1 ;and again
- do
- cmp.w d7,d6 ;are we done with that table completely ?
- bhi.s .doneinvalid
- moveq #0,d1 ;no deltas. These MUST be literally the same
- move.b rcs_ThisType(a7),d0 ;type of the descriptor we're pointing to
- move.l a1,a3 ;keep pointer for later
- jsr mulib_CmpDescriptor(a6) ;compare if the two descriptors are equal
- break.s ne ;abort if not
- addq.w #1,d6 ;continue with the next entry
- loop.s
- ;here: abort before the table went out of data
- clr.b rcs_continuous(a7) ;nope, this table is clearly not continous of one type
- .doneinvalid:
- ;here: found the properties of
- ;the entries [d5,d6]
- move.l #(1<<mapp_invalid),d0 ;properties are invalid
- moveq #0,d1 ;no user data
- bsr _SetPageRange
- beq .exit ;leave if this does not work
- reloop ;and continue in all other cases.
-
- .table: ;we got a table descriptor here
- ;this is a bit more complex
- ;first thing is that we scan this
- ;one recursively with ourselves
- move.l d6,d0 ;calculate address base
- move.l a7,a0 ;using this abstract descriptor
- move.b rcs_tableshift(a7),d1
- ror.l d1,d0 ;calculate the logical address here
- lea (a4,d0.l),a1 ;here we go
- move.w rcs_nextlevel(a7),d0 ;at the next level
- bsr RecursiveScan ;and call ourselves! Yoho!
- ;this can't become an infinite
- ;recursion because sooner or later
- ;we arrive at the bottom = page level of the
- ;tree and the ReadDescriptor function
- ;does then no longer generate "table" type entries
- beq .exit ;leave on exit
- addq.w #1,d6 ;and now the next level
- ;the current descriptor was processed inside
- ;we check now, if the next one looks identically
- cmp.b #2,d0 ;was this a continuous branch of the tree?
- bne.s .nexttable ;if not, then we can't shortcut it and have to continue
- ;the ordinary way
- cmp.w d7,d6 ;if we're done, we're done
- break.s hi
-
- movem.l d1/a0,rcs_lastproperties(a7) ;restore Properties/Pointer from level below
-
- ;o.k., now take the shortcut
- move.l a3,a0 ;from here
- move.l rcs_increment(a7),d0
- move.l d6,d5 ;start at this entry, which is the entry behind ours
- lea (a3,d0.l),a1 ;the next one to compare
- do
- cmp.w d7,d6
- bhi.s .donetable
- moveq #0,d1 ;no deltas. These MUST be literally the same
- move.b rcs_ThisType(a7),d0 ;type of the descriptor we're pointing to
- move.l a1,a3
- jsr mulib_CmpDescriptor(a6) ;compare if the two descriptors are equal
- break.s ne ;abort if not
- addq.w #1,d6 ;continue with the next entry
- loop.s
- ;here: abort before the table went out of data
- clr.b rcs_continuous(a7) ;nope, this table is clearly not continous of one type
- .donetable: ;we're done. Found [d5,d6] table entries of the same type already collected
- cmp.w d5,d6
- reloop eq ;continue, if nothing equal found
- movem.l rcs_lastproperties(a7),d0-d1 ;this user data
- ;these properties, filled in by the level below
- bsr _SetPageRange
- beq.s .exit
- reloop
-
- .nexttable:
- move.l rcs_increment(a7),d0
- adda.l d0,a3 ;next pointer
- clr.b rcs_continuous(a7) ;since the level below isn't continous, so are we.
- loop
-
-
- ;we're done. What's left is to map out
- ;the upper limit as illegal
- cmp.l rcs_entries(a7),d7 ;is there a useable upper limit ?
- beq.s .exitfine ;if not, nothing to map out
-
- clr.b rcs_continuous(a7) ;mapping is no longer continous
- move.l d7,d5 ;from here
- move.l rcs_entries(a7),d6 ;to here
- addq.l #1,d5
- moveq #0,d1 ;no user data
- addq.l #1,d6
- move.l #(1<<mapp_invalid),d0 ;clearly invalid
- bsr.s _SetPageRange
- beq.s .exit
- .exitfine:
- movem.l rcs_lastproperties(a7),d1/a0
- moveq #2,d0 ;default is continuous
- ;the level on top is informed about
- ;the user data and properties of
- ;this level because that
- ;gets filled in by
- ;the SetPageRange below
- kaputstr "}"
- tst.b rcs_continuous(a7) ;is it?
- bne.s .exit
- subq.l #1,d0 ;harder work for the next level
- .exit:
- freevar
- loadregs
- rts
-
- ;** SetPageRange
- ;** set pages [d5..d6] to properties given in d0, UData in d1
- _SetPageRange:
- saveregs d2/d5-d6
- defvar
- auto.b spr_map,map_len
- endvar
-
- spr_stack = map_len+3*4+4 ;stack offset to stackframe above
-
- move.b spr_stack+rcs_tableshift(a7),d2 ;get tableshift
- ror.l d2,d6 ;shift entry # to correct bit position
- ror.l d2,d5
- and.b #$fe,d6 ;in exceptional cases, one bit may leak thru
- lea (a4,d5.l),a0 ;higher
- lea (a4,d6.l),a1 ;lower
-
- movem.l d0-d1,map_properties(a7)
- subq.l #1,a1
- movem.l d0-d1,spr_stack+rcs_lastproperties(a7)
- movem.l a0-a1,map_lower(a7) ;upper, lower
-
- kaputstr <"[%08lx,%08lx) to %08lx, delta %08lx">,a0,a1,d0,d1
-
- moveq #-1,d0
- clr.l map_flags(a7)
- move.l d0,map_mask(a7) ;mask in everything
- move.l a5,a0
- move.l a7,a1
- bsr DefineMapping
-
- freevar
- loadregs
- rts
- ;ENDFOLD
- ;
-